﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Practices.Unity;
using System;
using MiniStock.BusinessLogic.EventDispatcher.MessageMap;
using MiniStock.BusinessLogic.EventQueue.Queue;
using MiniStock.Entities.Common;
using MiniStock.Infrastructure;
using MiniStock.Entities.Common.Events;
using MiniStock.Infrastructure.Configurator;

namespace MiniStock.BusinessLogic.EventDispatcher
{
    public class EventDispatcherWorker: QueuedEventWorkerBase
    {
        [Dependency]
        public EventProcessorCommunicationLogic BlEventProcessorCommunication { get; set; }

        [Dependency]
        public MessageMapHandler MapHandler { get; set; }

        public override void ProcessMessage(EntityEventBase message)
        {
            if (message.CorrelatedEventId == null)
                message.CorrelatedEventId = message.EventId;

            MapHandler.AddMessage(message);

            if(message is MessageFaultedEvent)
                return;

            var senderProcessor = BlEventProcessorCommunication.LookupProcessor(message.SenderAddress);
            if (senderProcessor != null && !senderProcessor.IsProcessorNode)
            {
                Trace.TraceInformation("{0} Message is persisted (Id: {1}, cid: {2})", Name, message.EventId,
                                       message.CorrelatedEventId);
                MapHandler.SetMessagePersisted(message);
                return;
            }

            List<EventProcessorDescriptor> clientData;
            if (message is MessageProcessedEvent)
            {
                clientData = BlEventProcessorCommunication.GetProcessorDescriptorForPersisters();
            }
            else
            {
                clientData =
                    BlEventProcessorCommunication.GetProcessorDescriptorForEntity(
                        ((EntityEventBase) message).GetEntityHash());
            }

            if (clientData == null || clientData.Count() == 0)
            {
                Trace.TraceError("Client not found for entity hash: " + ((EntityEventBase) message).GetEntityHash());
                return;
            }

            clientData.ForEach(i => i.Queue.Enqueue(message));
        }

        public void Configure(int index = 0)
        {
            var configurator = RootContainer.Resolve<IEventDispatcherConfigurator>();
            var qconfigurator = RootContainer.Resolve<IEventQueueConfigurator>();
            var pluginConfigurator = RootContainer.Resolve<IPluginConfigurator>();
            Name = configurator.GetName() + "." + index;
            BlEventProcessorCommunication.InitProcessorNodeMap();
            InputEventQueue.Configure(qconfigurator, configurator.GetQueueRef());

            var plugins = pluginConfigurator.GetEntryPoints();
            foreach (var initializer in plugins.Select(i => Type.GetType(i))
                .Where(s => s != null)
                .Select(i => RootContainer.Resolve(i) as IProcessorPluginEntryPoint)
                .Where(s => s != null)
                )
            {
                SerializationHelper.RegisterKnownEventTypes(initializer.EventRootTypes);
                SerializationHelper.RegisterKnownEntityTypes(initializer.EntityRootTypes);
            }

            EntityBaseExtender.InitSerializer();
            EventBaseExtender.InitSerializer();
        }

        public void Initialize()
        {
        }

    }
}
